package task2_2.com.at.count.polsk;

import java.util.List;
import java.util.Map;
import java.util.ArrayList;

public class PolNotationGenerator {

    private String expression;
    private Grammar grammar;

    public PolNotationGenerator(String expression, Grammar grammar) {
        this.expression = expression;
        this.grammar = grammar;
    }

    public List getInvertedPolNotayionList(Map functions) throws CounterException {

        List lexemes = Parser.parse(expression, functions);

        if (!grammar.test(lexemes)) {
            throw new CounterException();
        }

        return polNotation(lexemes);
    }

    private List polNotation(List lexemes) throws CounterException {

        List resultStack = new ArrayList();
        List stackSost = new ArrayList();

        for (int i=0; i<lexemes.size(); i++) {
            Object lexObj = lexemes.get(i);
            Lexeme lex = (Lexeme) lexemes.get(i);

            if (lex.getType() == Lexeme.TYPE_NUMBER) {
                resultStack.add(lex);
            } else if (lex.getType() == Lexeme.TYPE_TERM) {
                resultStack.add(lex);
            } else if (lex.getType() == Lexeme.TYPE_FUNCTION) {
                stackSost.add(lex);
            } else if (lex.getType() == Lexeme.TYPE_ZNAK) {

                if (lex.getValue().equals("+") || lex.getValue().equals("-")) {
                    if (stackSost.size() == 0) {
                        stackSost.add(lex);
                    } else {
                        while (stackSost.size() != 0 && !((Lexeme) stackSost.get(stackSost.size() - 1)).getValue().equals("(")) {
                            Lexeme curLastLex = (Lexeme) stackSost.get(stackSost.size() - 1);
                            stackSost.remove(stackSost.size() - 1);
                            resultStack.add(curLastLex);
                        }
                        stackSost.add(lex);
                    }
                } else if (lex.getValue().equals("*") || lex.getValue().equals("/")) {
                    if (stackSost.size() == 0) {
                        stackSost.add(lex);
                    } else {
                        Lexeme lastLex = (Lexeme) stackSost.get(stackSost.size() - 1);
                        if (lastLex.getValue().equals("+") || lastLex.getValue().equals("-") || lastLex.getValue().equals("(")) {
                            stackSost.add(lex);
                        } else {
                            stackSost.remove(stackSost.size() - 1);
                            resultStack.add(lastLex);
                            stackSost.add(lex);
                        }
                    }
                } else if(lex.getValue().equals("(")){
                     stackSost.add(lex);
                } else if(lex.getValue().equals(")")){
                    while (stackSost.size() != 0 && !((Lexeme) stackSost.get(stackSost.size() - 1)).getValue().equals("(")) {
                        Lexeme curLastLex = (Lexeme) stackSost.get(stackSost.size() - 1);
                        stackSost.remove(stackSost.size() - 1);
                        resultStack.add(curLastLex);
                    }
                    if (stackSost.size() > 0) {
                        stackSost.remove(stackSost.size() - 1);
                    } else {
                        throw new CounterException();
                    }
                }
            } else {
                throw new CounterException();
            }
        }

        while (stackSost.size() != 0 && !((Lexeme) stackSost.get(stackSost.size() - 1)).getValue().equals("(")) {
            Lexeme curLastLex = (Lexeme) stackSost.get(stackSost.size() - 1);
            stackSost.remove(stackSost.size() - 1);
            resultStack.add(curLastLex);
        }
        if (stackSost.size() > 0) {
            throw new CounterException();
        }

        return resultStack;
    }

}
